#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "NUC900_reg.h"
#include "wblib.h"
#include "NUC900_SIC.h"


#define FMI_TEST_SIZE	(512 * 128)
__align(4096) UINT8 fmiFlash_Buf[FMI_TEST_SIZE];
__align(4096) UINT8 fmiReadBackBuffer[FMI_TEST_SIZE];

unsigned char *pSrc_fmi, *pDst_fmi;

extern int diag_sd(void);
extern int diag_sd_cd(void);
extern int diag_ms(void);
extern int diag_ms_cd(void);
extern int diag_nand(void);
extern int diag_sd1_cd(void);

struct fmi_test_list
{
	char  	name[64];
	int 	(*diag_func)(void);
};

#if defined(NUC951)
struct fmi_test_list  test_items_fmi_950[] =
{
	"",					NULL,
	"(1)  SD Card Test                     ", diag_sd,
	"(2)  SD Card Detection                ", diag_sd_cd,
	"(3)  NAND Test                        ", diag_nand,
	"(4)  Exit                             ", NULL
};
#else
struct fmi_test_list  test_items_fmi_950[] =
{
	"",					NULL,
	"(1)  SD Card Test                     ", diag_sd,
	"(2)  SD Card Detection                ", diag_sd_cd,
	"(3)  Memory Stick Test                ", diag_ms,
	"(4)  Memory Stick Card Detection Test ", diag_ms_cd,
	"(5)  NAND Test                        ", diag_nand,
	"(6)  Exit                             ", NULL
};
#endif

unsigned int volatile SD_Flag=0, MS_Flag=0;


void SD_InsertDevice()
{
	SD_Flag = 1;
}


void SD_RemoveDevice()
{
	SD_Flag = 0;
}


void MS_InsertDevice()
{
	MS_Flag = 1;
}

void MS_RemoveDevice()
{
	MS_Flag = 0;
}


static int  _fmi_inited = 0;

void diag_init_fmi(void)
{
	unsigned int volatile i, data;

	if (_fmi_inited)
		return;
	
	// set FMI reference clock
	sicIoctl(SIC_SET_CLOCK, 200000, 0, 0);
	sicIoctl(SIC_SET_CALLBACK, FMI_SD_CARD0, (INT32)SD_RemoveDevice, (INT32)SD_InsertDevice);
	sicIoctl(SIC_SET_CALLBACK, FMI_MS_CARD0, (INT32)MS_RemoveDevice, (INT32)MS_InsertDevice);
	pSrc_fmi = (UINT8 *)((UINT32)fmiFlash_Buf | 0x80000000);
	pDst_fmi = (UINT8 *)((UINT32)fmiReadBackBuffer | 0x80000000);

	data = 0;
	for (i=0; i<FMI_TEST_SIZE; i++)
	{
		*(pSrc_fmi+i) = (data + i) & 0xff;
		if (((i+1) % 0xff) == 0)
			data++;
	}

	// initial FMI
	_fmi_inited = 1;
	
	sicOpen();
}


int diag_fmi()
{
	unsigned int volatile i;
	struct fmi_test_list	*test_items;
	INT					item_len, idx;

	diag_init_fmi();

	if ((inpw(REG_PDID) & 0xfff) == 0x910)
	{
		// test item
		test_items = test_items_fmi_950;
		item_len   = sizeof(test_items_fmi_950) / sizeof(struct fmi_test_list);

		while (1)
		{
			sysprintf("\n\n\n\n");

			/*--------------------------------------------------------------------------------*/
			/* print list test items                                                          */
			/*--------------------------------------------------------------------------------*/
			sysprintf("+------------------------------------------+\n");
			sysprintf("|  FMI test items                          |\n");
			sysprintf("+------------------------------------------+\n");
#if defined (NUC951)			
			for (i = 1; i <= 4; i++)
#else
			for (i = 1; i <= 6; i++)
#endif
			sysprintf("| %s   |\n", test_items[i].name);
			sysprintf("+------------------------------------------+\n");
		
			sysprintf("\nPlease select the test item: ");
			idx = get_item_number(item_len);
			if ((idx < 0) || (idx > 6))
				continue;
			if (idx == 6)
				break;

			sysprintf("\nSelect test item %d\n\n\n", idx);
		
			if (test_items[idx].diag_func != NULL)
				test_items[idx].diag_func();
			else
			{
				//sysprintf("\n\n\n%s diagnostic code not available!\n", test_items[idx].name);
				break;
			}
			sysprintf("\n\nPress any key to continue...\n");
			sysGetChar();
		}
	}
	return 0;
}

int diag_sd()
{
	BOOL err_flag=0;
	int volatile i, sector;
	int volatile btime, status;

	sysprintf("\nSD card test ...\n");
#if defined(NUC951)
	sysprintf("Please make sure switch SW8 is on.\n");
#else
	sysprintf("Please make sure switch SW1 is on and SW2 is off.\n");
#endif	
	sysprintf("\n\nPress any key to start test...\n");
	sysGetChar();

	/* begin test */
	memset(pDst_fmi, 0, FMI_TEST_SIZE);

	sector = sicSdOpen(0);
	if (sector < 0)
	{
		sysprintf("SD card init failed [%d]\n", sector);
		err_flag = 1;
		goto _exit_sd0_;
	}	
	sysprintf("SD card found, total sectors [%d]\n", sector);

	sysprintf("SD write\n");
	btime = sysGetTicks(TIMER0);
	status = sicSdWrite(0, 9000, FMI_TEST_SIZE/512, (unsigned int)pSrc_fmi);
	btime = sysGetTicks(TIMER0) - btime;
	if (btime == 0) btime = 1;

	sysprintf("[%d] SD write speed %d KB/sec [%d]\n", status, (FMI_TEST_SIZE * 100) / (btime * 1024), btime);

	sysprintf("SD read\n");
	btime = sysGetTicks(TIMER0);
	status = sicSdRead(0, 9000, FMI_TEST_SIZE/512, (unsigned int)pDst_fmi);
	btime = sysGetTicks(TIMER0) - btime;
	if (btime == 0) btime = 1;

	sysprintf("[%d] SD read speed %d KB/sec\n", status, (FMI_TEST_SIZE * 100) / (btime * 1024));

	sysprintf("Compare data ...\n");
	for (i=0; i<FMI_TEST_SIZE; i++)
	{
		if (*(pSrc_fmi+i) != *(pDst_fmi+i))
		{
			sysprintf("error!! <%d> Src[%x], Dst[%x]\n", i, *(pSrc_fmi+i), *(pDst_fmi+i));
			err_flag = 1;
			break;
		}
	}

_exit_sd0_:
	if (err_flag == 1)
		sysprintf("SD test failed!!!\n");
	else
		sysprintf("SD test OK!!!\n");
	return 0;
}


NDRV_T _nandDiskDriver0 = 
{
	nandInit0,
	nandpread0,
	nandpwrite0,
	nand_is_page_dirty0,
	nand_is_valid_block0,
	nand_ioctl,
	nand_block_erase0,
	nand_chip_erase0,
	0
};

int diag_nand()
{
	BOOL err_flag=0;
	int volatile i, totalSec;
	int volatile btime, status;
	NDISK_T *ptNDisk;
	
	sysprintf("\nTest NAND ...\n");
	sysprintf("Please check the NAND switch...\n");
	sysprintf("It should turn ON...\n");
	sysprintf("\n\nPress any key to begin test...\n");
	sysGetChar();
	
	outpw(REG_MFSEL, (inpw(REG_MFSEL) & 0xFFFFFFF3) | 0x04);

	ptNDisk = (NDISK_T *)malloc(sizeof(NDISK_T));
	if (ptNDisk == NULL)
		sysprintf("malloc error!!\n");
	
	sysprintf("GNAND Init %x\n", GNAND_InitNAND(&_nandDiskDriver0, ptNDisk, TRUE));

	totalSec = FMI_TEST_SIZE/512;
	sysprintf("NAND write\n");
	btime = sysGetTicks(TIMER0);
	status = GNAND_write(ptNDisk, 0, FMI_TEST_SIZE/512, pSrc_fmi);
	btime = sysGetTicks(TIMER0) - btime;
	if (btime == 0) btime = 1;

	sysprintf("[%x] NAND write speed %d KB/sec\n", status, (FMI_TEST_SIZE * 100) / (btime * 1024));

	sysprintf("NAND read\n");
	btime = sysGetTicks(TIMER0);
	status = GNAND_read(ptNDisk, 0, FMI_TEST_SIZE/512, pDst_fmi);
	btime = sysGetTicks(TIMER0) - btime;
	if (btime == 0) btime = 1;

	sysprintf("[%x] NAND read speed %d KB/sec\n", status, (FMI_TEST_SIZE * 100) / (btime * 1024));

	sysprintf("compare\n");
	for (i=0; i<FMI_TEST_SIZE; i++)
	{
		if (*(pSrc_fmi+i) != *(pDst_fmi+i))
		{
			sysprintf("error!! <%x> Src[%x], Dst[%x]\n", i, *(pSrc_fmi+i), *(pDst_fmi+i));
			break;
		}
	}

	if (err_flag == 1)
		sysprintf("NAND test failed!!!\n");
	else
		sysprintf("NAND test OK!!!\n");

	outpw(REG_MFSEL, (inpw(REG_MFSEL) & 0xFFFFFFF3) | 0x0C);

	return 0;
}


int diag_ms()
{
	BOOL err_flag=0;
	int volatile i, sector;
	int volatile btime, status;

	sysprintf("\nMemory stick card test ...\n");
	sysprintf("Please make sure switch SW2 is on and SW1 is off.\n");
	sysprintf("\n\nPress any key to start test...\n");
	sysGetChar();

	/* begin test */
	memset(pDst_fmi, 0, FMI_TEST_SIZE);

	sector = sicMsOpen(0);
	if (sector < 0)
	{
		sysprintf("Memory stick init failed [%d]\n", sector);
		err_flag = 1;
		goto _exit_ms0_;
	}	
	sysprintf("Memory stick detected, total sectors [%d]\n", sector);

	sysprintf("MS write\n");
	btime = sysGetTicks(TIMER0);
	status = sicMsWrite(0, 20000, FMI_TEST_SIZE/512, (unsigned int)pSrc_fmi);
	btime = sysGetTicks(TIMER0) - btime;
	if (btime == 0) btime = 1;

	sysprintf("[%d] MS write speed %d KB/sec\n", status, (FMI_TEST_SIZE * 100) / (btime * 1024));

	sysprintf("MS read\n");
	btime = sysGetTicks(TIMER0);
	status = sicMsRead(0, 20000, FMI_TEST_SIZE/512, (unsigned int)pDst_fmi);
	btime = sysGetTicks(TIMER0) - btime;
	if (btime == 0) btime = 1;

	sysprintf("[%d] MS read speed %d KB/sec\n", status, (FMI_TEST_SIZE * 100) / (btime * 1024));


	sysprintf("Compare ...\n");
	for (i=0; i<FMI_TEST_SIZE; i++)
	{
		if (*(pSrc_fmi+i) != *(pDst_fmi+i))
		{
			sysprintf("error!! <%d> Src[%x], Dst[%x]\n", i, *(pSrc_fmi+i), *(pDst_fmi+i));
			err_flag = 1;
			break;
		}
	}

_exit_ms0_:
	if (err_flag == 1)
		sysprintf("Memory stick test failed!!!\n");
	else
		sysprintf("Memory stick test OK!!!\n");

	return 0;
}


int diag_sd_cd()
{
	int status = 0, remove_count=0, insert_count=0;
	unsigned char *ptr;

	sysprintf("\nSD card detect test ...\n");
#if defined(NUC951)
	sysprintf("Please make sure switch SW8 is on.\n");
#else	
	sysprintf("Please make sure switch SW1 is on and SW2 is off.\n");
#endif	
	sysprintf("\n\nPress any key to start test...\n");
	sysGetChar();

	ptr = (unsigned char *)0x80100000;
	status = sicSdOpen(0);
	if (status == FMI_NO_SD_CARD)
	{
		sysprintf("No SD Card!!\n");
		remove_count++;
		while(1)
		{
			if (SD_Flag == 1)
			{
				status = sicSdOpen(0);
				sysprintf("SD card inserted [%d]!!\n", status);
				insert_count++;
				break;
			}
		}
	}
	else
	{
		sysprintf("SD Card inserted!!\n");
		insert_count++;
		SD_Flag = 1;
	}

	while(1)
	{
		status = sicSdRead(0,  1000, 512, (unsigned int)ptr);
		if (status == FMI_NO_SD_CARD)
		{
			sysprintf("SD card removed!!\n");
			remove_count++;
			while(1)
			{
				if (SD_Flag == 1)
				{
					status = sicSdOpen(0);
					sysprintf("SD card insert [%d]!!\n", status);
					insert_count++;
					break;
				}
			}
		}

		if ((remove_count>1) || (insert_count>1))
		{
			sysprintf("Please any key to exit the test ...\n");
			sysGetChar();
			break;
		}
	}

	return 0;
}


int diag_ms_cd()
{
	int status = 0, remove_count=0, insert_count=0;
	unsigned char *ptr;

	sysprintf("\nMemory stick card detect test ...\n");
	sysprintf("Please make sure switch SW2 is on and SW1 is off.\n");
	sysprintf("\n\nPress any key to start test...\n");
	sysGetChar();

	ptr = (unsigned char *)0x80100000;
	status = sicMsOpen(0);
	if (status == FMI_NO_MS_CARD)
	{
		sysprintf("No memory stick Card!!\n");
		remove_count++;
		while(1)
		{
			if (MS_Flag == 1)
			{
				status = sicMsOpen(0);
				sysprintf("Memory stick card inserted [%d]!!\n", status);
				insert_count++;
				break;
			}
		}
	}
	else
	{
		sysprintf("Memory stick card inserted!!\n");
		insert_count++;
		MS_Flag = 1;
	}

	while(1)
	{
		status = sicMsRead(0,  1000, 512, (unsigned int)ptr);
		if (status == FMI_NO_MS_CARD)
		{
			sysprintf("Memory stick card removed!!\n");
			remove_count++;
			while(1)
			{
				if (MS_Flag == 1)
				{
					status = sicMsOpen(0);
					sysprintf("Memory stick card inserted [%d]!!\n", status);
					insert_count++;
					break;
				}
			}
		}

		if ((remove_count>1) || (insert_count>1))
		{
			sysprintf("Please any key to exit the test ...\n");
			sysGetChar();
			break;
		}
	}

	return 0;
}



